using TestCases.CompareAssert.Core.Builders;
using TestCases.CompareAssert.Core.Comparers.Interfaces;
using TestCases.CompareAssert.Core.Interfaces;

namespace TestCases.CompareAssert.Core.Comparers.Adapters
{

    public delegate bool CompareDelegate(object left, object right);
    public delegate bool CompareDelegate<T>(T left, T right);
    
    public class DelegateComparer: IObjectComparer
    {
        private readonly CompareDelegate _func;

        public DelegateComparer(CompareDelegate func)
        {
            _func = func;
        }
        
        public string Name
        {
            get { return "DelegateComparer"; }
        }

        public IResultBuilder Compare(ICompareContext context)
        {
            return this.IsBoolResult(_func.Invoke(context.LValue, context.RValue), context).
                ForEquals("<{LPath}> equals to <{RPath}> [{Predicate}({LValue}, {RValue}) == true].").
                ForNotEquals("<{LPath}> not equals to <{RPath}> [{Predicate}({LValue}, {RValue}) == false].").
                With(new {Predicate = _func});
        }
    }


    public class DelegateComparer<T> : IObjectComparer
    {
        private readonly CompareDelegate<T> _func;

        public DelegateComparer(CompareDelegate<T> func)
        {
            _func = func;
        }

        public string Name
        {
            get
            {
                return "DelegateComparer";
            }
        }

        public IResultBuilder Compare(ICompareContext context)
        {
            if (!(context.LValue is T))
            {
                return this.IsNotApplicable(context).Left.IsNot<T>();
            }
            if (!(context.RValue is T))
            {
                return this.IsNotApplicable(context).Right.IsNot<T>();
            }
            return this.IsBoolResult(_func.Invoke((T) context.LValue, (T) context.RValue), context).
                ForEquals("<{LPath}> equals to <{RPath}> [{Predicate}({LValue}, {RValue}) == true].").
                ForNotEquals("<{LPath}> not equals to <{RPath}> [{Predicate}({LValue}, {RValue}) == false].").
                With(new {Predicate = _func});
        }
    }

}